package ex;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Objects;
import java.util.Scanner;

/**
 * @Description 程序入口
 * @Date 2022/3/19 21:06
 * @Author eric ling
 */
public class SimpleSearch {

    /*
        边界验证：nCk 当k=0时
        DSP(13,6,6,0,3) D1={1,3,9,4,12,10} D2={2,6,5,7,8,11}
        DSP(17,8,8,0,4) D1={1,2,4,8,16,15,13,9} D2={3,6,12,7,14,11,5,10}

        小范围
        DSP(15,3,5,1,1) D1={0,5,10} D2={0,3,6,9,12}
        DSP(13,6,7,6,3) D={1,3,4,9,10,12} D2={1,3,4,9,10,12,0}

        大范围
        DSP(31,11,6,6,2)
        DSP(51,26,16,16,8)
        DSP(57,29,20,20,10)
        DSP(69,35,24,24,12)
        DSP(73,54,19,18,14)
    */
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入系统变量v,k1,k2,e,lambda，组合数太大会内存溢出或超出int表示范围，请保持v<=31，例如：15,3,5,1,1");
        String[] numStrs = scanner.nextLine().split("[,;\\s]+");
        int[] nums = new int[5];
        int tmpIdx = 0;
        for (String numStr : numStrs) {
            nums[tmpIdx++] = Integer.parseInt(numStr);
        }
        DiffSetPair p = null;
        // 利用必要条件预筛选给定差集偶的参数
        if (DiffSetPair.isValid(nums)) {
            p = new DiffSetPair(nums);
        }
        Objects.requireNonNull(p, "参数不合法");
        System.out.println("searching...");
        File file = new File("result.txt");
        if (!file.exists()) {
            try {
                System.out.println("create file result.txt:" + file.createNewFile());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try (FileWriter writer = new FileWriter(file)) {
            System.out.println("共搜索到"+run(p, writer)+"个满足给定参数的差集偶");
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("搜索耗时：" + (end - start) + "毫秒");
        System.out.println("差集偶搜索完毕，结果保存在result.txt");
    }

    /**
     * todo 组合数过大会溢出
     * todo 打成jar包（不包括迭代搜索）
     */
    public static int run(DiffSetPair p, Writer writer) throws IOException {
        int find = 0;
        // 所有的数从该集合中选取
        boolean[] remainderSetIdx = new boolean[p.getV()]; // 用下标表示集合元素，存放的boolean表示是否存在集合中
        Arrays.fill(remainderSetIdx, true);

        // 从v个数中确定集合setE的所有组合
        // allCombE = AllCombList(v,e)
        int[][] eSetIdxAllComb = CombinationUtil.allCombList(p.getV(), p.getE());
        // 遍历集合setE的所有可能组合
        // 取出一种可能的组合，存放的是序号
        for (int[] eSetIdx : eSetIdxAllComb) {
            boolean[] remainderSetIdx1 = remainderSetIdx.clone();
            // 确定集合e
            int[] eSet = ArrayHandler.extractCombElement(remainderSetIdx1, eSetIdx);
            p.seteSet(eSet);
            // 从v-e个数中确定集合k2Set-eSet的所有组合
            // allCombD2_E = C(v-e,k2-e)
            int[][] k2Set_eSetIdxAllComb = CombinationUtil.allCombList(p.getV() - p.getE(), p.getK2() - p.getE());

            // 遍历集合k2Set-eSet的所有可能组合
            // 取出一种可能的组合，存放的是序号
            for (int[] k2Set_eSetIdx : k2Set_eSetIdxAllComb) {
                boolean[] remainderSetIdx2 = remainderSetIdx1.clone();
                // 确定集合k2Set
                int[] k2Set_eSet = ArrayHandler.extractCombElement(remainderSetIdx2, k2Set_eSetIdx);
                int[] k2Set = ArrayHandler.concat(k2Set_eSet, eSet);
                p.setK2Set(k2Set);

                // 从v-k2个数中抽取k1-e个数
                // allCombD1_E = C(v-k2,k1-e)
                int[][] k1Set_eSetIdxAllComb = CombinationUtil.allCombList(p.getV() - p.getK2(), p.getK1() - p.getE());
                // 遍历集合k1Set-eSet的所有可能组合
                // 取出一种可能的组合，存放的是序号
                for (int[] k1Set_eSetIdx : k1Set_eSetIdxAllComb) {
                    boolean[] remainderSetIdx3 = remainderSetIdx2.clone();
                    // 确定集合k1Set
                    int[] k1Set_eSet = ArrayHandler.extractCombElement(remainderSetIdx3, k1Set_eSetIdx);
                    int[] k1Set = ArrayHandler.concat(k1Set_eSet, eSet);
                    p.setK1Set(k1Set);
                    // k1Set和k2Set都确定了，开始判断是否构成差集偶
                    if (p.isDiffSetPair()) {
                        find++;
                        System.out.println(p);
                        writer.write(p + "\n");
                    }
                }
            }
        }
        return find;
    }
}
